﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Windows.Automation.Peers;
using System.Linq;
using System.Windows.Data;
using SLControlLibrary.Resources.Controls.Calendar.Common;
using SLControlLibrary.Resources.Controls.Calendar.ClassicCalendar.BusinessObjects;
using SLControlLibrary.Resources.Controls.Calendar.ClassicCalendar.BusinessEntities;
using SLControlLibrary.Resources.Controls.Calendar.ClassicCalendar.DataAccess;
using SLControlLibrary.Resources.Controls.Calendar.ClassicCalendar.ViewModel;

namespace SLControlLibrary.Resources.Controls.Calendar.ClassicCalendar
{
    public class ucCalendar : Control
    {
        #region Dependency Variables
        private static readonly DependencyProperty DisplayModeProperty = DependencyProperty.Register("DisplayMode", typeof(Enumerations.DisplayMode), typeof(ucCalendar), new PropertyMetadata(Enumerations.DisplayMode.Display));
        private static readonly DependencyProperty SelectionModeProperty = DependencyProperty.Register("SelectionMode", typeof(Enumerations.SelectionMode), typeof(ucCalendar), new PropertyMetadata(Enumerations.SelectionMode.Multiple));
        private static readonly DependencyProperty DateViewProperty = DependencyProperty.Register("DateView", typeof(Enumerations.CurrentDateView), typeof(ucCalendar), new PropertyMetadata(Enumerations.CurrentDateView.Decade, new PropertyChangedCallback(DateView_Changed)));
        private static readonly DependencyProperty ControlHeightProperty = DependencyProperty.Register("ControlHeight", typeof(double), typeof(ucCalendar), new PropertyMetadata(200D, new PropertyChangedCallback(ControlHeight_Changed)));
        private static readonly DependencyProperty ControlWidthProperty = DependencyProperty.Register("ControlWidth", typeof(double), typeof(ucCalendar), new PropertyMetadata(212D, new PropertyChangedCallback(ControlWidth_Changed)));
        private static readonly DependencyProperty HeaderBackgroundProperty = DependencyProperty.Register("HeaderBackground", typeof(SolidColorBrush), typeof(ucCalendar), new PropertyMetadata(null, new PropertyChangedCallback(HeaderBackground_Changed)));
        private static readonly DependencyProperty AnimationTypeProperty = DependencyProperty.Register("AnimationType", typeof(Enumerations.AnimationType), typeof(ucCalendar), new PropertyMetadata(Enumerations.AnimationType.None));
        private static readonly DependencyProperty HeaderForegroundProperty = DependencyProperty.Register("HeaderForeground", typeof(SolidColorBrush), typeof(ucCalendar), new PropertyMetadata(new SolidColorBrush(Colors.Black), new PropertyChangedCallback(HeaderForeground_Changed)));
        private static readonly DependencyProperty WeekHeaderForegroundProperty = DependencyProperty.Register("WeekHeaderForeground", typeof(SolidColorBrush), typeof(ucCalendar), new PropertyMetadata(new SolidColorBrush(Colors.Black), new PropertyChangedCallback(WeekHeaderForeground_Changed)));
        private static readonly DependencyProperty YearForegroundProperty = DependencyProperty.Register("YearForeground", typeof(SolidColorBrush), typeof(ucCalendar), new PropertyMetadata(new SolidColorBrush(Colors.Black), new PropertyChangedCallback(YearForeground_Changed)));
        private static readonly DependencyProperty MonthForegroundProperty = DependencyProperty.Register("MonthForeground", typeof(SolidColorBrush), typeof(ucCalendar), new PropertyMetadata(new SolidColorBrush(Colors.Black), new PropertyChangedCallback(MonthForeground_Changed)));
        private static readonly DependencyProperty SelectedDateProperty = DependencyProperty.Register("SelectedDate", typeof(DateTime), typeof(ucCalendar), new PropertyMetadata(DateTime.Today, new PropertyChangedCallback(SelectedDate_Changed)));
        public static readonly DependencyProperty AllowMonthNavigationProperty = DependencyProperty.Register("AllowMonthNavigation", typeof(bool), typeof(ucCalendar), new PropertyMetadata(true, new PropertyChangedCallback(AllowMonthNavigation_Changed)));
        #endregion

        #region Dependency Properties
        public Enumerations.DisplayMode DisplayMode
        {
            get { return (Enumerations.DisplayMode)this.GetValue(DisplayModeProperty); }
            set { SetValue(DisplayModeProperty, value); }
        }
        public Enumerations.SelectionMode SelectionMode
        {
            get { return (Enumerations.SelectionMode)this.GetValue(SelectionModeProperty); }
            set { SetValue(SelectionModeProperty, value); }
        }
        public Enumerations.CurrentDateView DateView
        {
            get { return (Enumerations.CurrentDateView)this.GetValue(DateViewProperty); }
            set { SetValue(DateViewProperty, value); }
        }
        public double ControlHeight
        {
            get { return (double)this.GetValue(ControlHeightProperty); }
            set { SetValue(ControlHeightProperty, value); }
        }
        public double ControlWidth
        {
            get { return (double)this.GetValue(ControlWidthProperty); }
            set { SetValue(ControlWidthProperty, value); }
        }
        public SolidColorBrush HeaderBackground
        {
            get { return (SolidColorBrush)this.GetValue(HeaderBackgroundProperty); }
            set { SetValue(HeaderBackgroundProperty, value); }
        }
        public Enumerations.AnimationType AnimationType
        {
            get { return (Enumerations.AnimationType)this.GetValue(AnimationTypeProperty); }
            set { SetValue(AnimationTypeProperty, value); }
        }
        public SolidColorBrush WeekHeaderForeground
        {
            get { return (SolidColorBrush)this.GetValue(WeekHeaderForegroundProperty); }
            set { SetValue(WeekHeaderForegroundProperty, value); }
        }
        public SolidColorBrush HeaderForeground
        {
            get { return (SolidColorBrush)this.GetValue(HeaderForegroundProperty); }
            set { SetValue(HeaderForegroundProperty, value); }
        }
        public SolidColorBrush YearForeground
        {
            get { return (SolidColorBrush)this.GetValue(YearForegroundProperty); }
            set { SetValue(YearForegroundProperty, value); }
        }
        public SolidColorBrush MonthForeground
        {
            get { return (SolidColorBrush)this.GetValue(MonthForegroundProperty); }
            set { SetValue(MonthForegroundProperty, value); }
        }
        public DateTime SelectedDate
        {
            get { return (DateTime)this.GetValue(SelectedDateProperty); }
            set { this.SetValue(SelectedDateProperty, value); }
        }
        public bool AllowMonthNavigation
        {
            get { return (bool)this.GetValue(AllowMonthNavigationProperty); }
            set { this.SetValue(AllowMonthNavigationProperty, value); }
        }
        #endregion

        #region Dependency Events
        #region SelectedDate_Changed
        private static void SelectedDate_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as ucCalendar).OnSelectedDate_Changed(e);
        }
        #endregion

        #region DateView_Changed
        private static void DateView_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as ucCalendar).OnDateView_Changed(e);
        }
        #endregion

        #region ControlHeight_Changed
        private static void ControlHeight_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as ucCalendar).OnControlHeight_Changed(e);
        }
        #endregion

        #region ControlWidth_Changed
        private static void ControlWidth_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as ucCalendar).OnControlWidth_Changed(e);
        }
        #endregion

        #region HeaderBackground_Changed
        private static void HeaderBackground_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as ucCalendar).OnHeaderBackground_Changed(e);
        }
        #endregion

        #region WeekHeaderForeground_Changed
        private static void WeekHeaderForeground_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as ucCalendar).OnWeekHeaderForeground_Changed(e);
        }
        #endregion

        #region HeaderForeground_Changed
        private static void HeaderForeground_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as ucCalendar).OnHeaderForeground_Changed(e);
        }
        #endregion

        #region YearForeground_Changed
        private static void YearForeground_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as ucCalendar).OnYearForeground_Changed(e);
        }
        #endregion

        #region MonthForeground_Changed
        private static void MonthForeground_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as ucCalendar).OnMonthForeground_Changed(e);
        }
        #endregion

        #region AllowMonthNavigation_Changed
        private static void AllowMonthNavigation_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as ucCalendar).OnAllowMonthNavigation_Changed(e);
        }
        #endregion
        #endregion

        #region Variables
        private DayOfWeek? _FirstDayOfWeek = null;
        private int _ThisYear = 0;
        private int _FirstYear = 0;
        private int _LastYear = 0;
        private int _Decade = 10;
        private ucHeader _Header = null;
        private Border _BrdRoot = null;
        private Grid grdCollection = null;
        private Storyboard sbAnimate = null;
        private SplineDoubleKeyFrame AnimateWidth = null;
        private SplineDoubleKeyFrame AnimateHeight = null;
        private SplineDoubleKeyFrame AnimateLeft = null;
        private SplineDoubleKeyFrame AnimateTopStart = null;
        private SplineDoubleKeyFrame AnimateTopEnd = null;
        private DaySelectionCollection _SelectionCollection = null;
        private DateRangeCollection _DateRangeCollection = null;
        private YearCollection _YearCollection;
        private MonthCollection _MonthCollection;
        private DayCollection _DayCollection;
        private bool IsControlLoaded = false;

        private bool _DayMouseLeftButtonDown = false;
        public DateTime? _MultiSelectionStartDate = null;
        public DateTime? _MultiSelectionEndDate = null;
        internal DateTime? _LastSelectedDate = null;
        public Collection<DateTime> _RemovedDates = new Collection<DateTime>();
        internal bool _IsMouseSelection = false;
        #endregion

        #region Properties
        public int _CurrentYear { get; set; }
        public int _CurrentMonth { get; set; }
        public string CalendarType { get; set; }
        public BusinessEntities.SelectedDatesCollection SelectedDates { get; private set; }
        #endregion

        #region Event Variables
        public event EventHandler<SelectionChangedEventArgs> SelectedDatesChanged = null;
        private MouseButtonEventArgs DownEventArg = null;
        #endregion

        #region Constructor
        public ucCalendar()
        {
            DefaultStyleKey = typeof(ucCalendar);
            this.Loaded += new RoutedEventHandler(ucCalendar_Loaded);
        }
        #endregion

        #region Events
        #region ucCalendar_Loaded
        void ucCalendar_Loaded(object sender, RoutedEventArgs e)
        {
            SetBindings();
        }
        #endregion

        #region Year_Selected
        private void Year_Selected(object sender, Events.CalendarItemClickedEventArgs e)
        {
            DateView = Enumerations.CurrentDateView.Year;

            _CurrentYear = (sender as ucCalendarItem).Value;

            SetHeaderValue(_CurrentYear.ToString());

            MonthCollection _MonthCollection = PopulateMonths(_CurrentYear);

            grdCollection.Children.Clear();

            grdCollection.ColumnDefinitions.Clear();
            grdCollection.RowDefinitions.Clear();

            double ColumnWidth = ControlWidth / 4;
            double RowHeight = (ControlHeight - _Header.DisplayHeight) / 3;

            ColumnDefinition cd1 = new ColumnDefinition();
            cd1.Width = new GridLength(ColumnWidth, GridUnitType.Pixel);
            grdCollection.ColumnDefinitions.Add(cd1);
            cd1 = new ColumnDefinition();
            cd1.Width = new GridLength(ColumnWidth, GridUnitType.Pixel);
            grdCollection.ColumnDefinitions.Add(cd1);
            cd1 = new ColumnDefinition();
            cd1.Width = new GridLength(ColumnWidth, GridUnitType.Pixel);
            grdCollection.ColumnDefinitions.Add(cd1);
            cd1 = new ColumnDefinition();
            cd1.Width = new GridLength(ColumnWidth, GridUnitType.Pixel);
            grdCollection.ColumnDefinitions.Add(cd1);

            RowDefinition rd1 = new RowDefinition();
            rd1.Height = new GridLength(RowHeight, GridUnitType.Pixel);
            grdCollection.RowDefinitions.Add(rd1);
            rd1 = new RowDefinition();
            rd1.Height = new GridLength(RowHeight, GridUnitType.Pixel);
            grdCollection.RowDefinitions.Add(rd1);
            rd1.Height = new GridLength(RowHeight, GridUnitType.Pixel);
            rd1 = new RowDefinition();
            grdCollection.RowDefinitions.Add(rd1);

            int rowCount = 0;
            int colCount = 0;

            foreach (ucCalendarItem _Month in _MonthCollection)
            {
                _Month.ValueEvent += Month_Selected;
                _Month.Foreground = MonthForeground;
                _Month.Height = RowHeight;
                _Month.Width = ColumnWidth;

                Grid.SetRow(_Month, rowCount);
                Grid.SetColumn(_Month, colCount);
                grdCollection.Children.Add(_Month);

                if (colCount == 3)
                {
                    colCount = 0;
                    rowCount++;
                }
                else
                    colCount++;
            }

            PlayAnimation();
        }
        #endregion

        #region Month_Selected
        private void Month_Selected(object sender, Events.CalendarItemClickedEventArgs e)
        {
            DateView = Enumerations.CurrentDateView.Month;
            _CurrentMonth = (sender as ucCalendarItem).Value;

            SetHeaderValue(Enum.Parse(typeof(Enumerations.MonthsInYearLongDesc), _CurrentMonth.ToString(), true).ToString() + ", " + _CurrentYear);

            _DayCollection.Clear();
            grdCollection.Children.Clear();
            grdCollection.ColumnDefinitions.Clear();
            grdCollection.RowDefinitions.Clear();

            double ColumnWidth = ControlWidth / 7;

            DateTime tempDate = new DateTime(_CurrentYear, _CurrentMonth, 1);
            DayOfWeek _FirstDayOfMonth = tempDate.DayOfWeek;
            int _DaysInMonth = DateTime.DaysInMonth(_CurrentYear, _CurrentMonth);

            for (int i = 0; i < 7; i++)
            {
                ColumnDefinition cd1 = new ColumnDefinition();
                cd1.Width = new GridLength(ColumnWidth, GridUnitType.Pixel);
                grdCollection.ColumnDefinitions.Add(cd1);
            }

            int _RowsInMonth = 6;

            if (_DaysInMonth == 30 && _FirstDayOfMonth >= DayOfWeek.Friday)
                _RowsInMonth++;

            if (_DaysInMonth == 31 && _FirstDayOfMonth >= DayOfWeek.Thursday)
                _RowsInMonth++;

            double RowHeight = (ControlHeight - _Header.DisplayHeight) / _RowsInMonth;

            for (int i = 0; i < _RowsInMonth; i++)
            {
                RowDefinition rd1 = new RowDefinition();
                rd1.Height = new GridLength(RowHeight);
                grdCollection.RowDefinitions.Add(rd1);
            }

            int rowCount = 0;
            int colCount = 0;

            DayCollection _HeaderCollection = PopulateWeekHeaderCollection(ColumnWidth, RowHeight, Orientation.Horizontal, WeekHeaderForeground);

            foreach (ucDay _Day in _HeaderCollection)
            {
                Grid.SetRow(_Day, rowCount);
                Grid.SetColumn(_Day, colCount);
                grdCollection.Children.Add(_Day);
                colCount++;
            }

            rowCount = 1;
            colCount = 0;

            foreach (ucDay _Day in PopulateWeekSpacer(ColumnWidth, RowHeight, _DaysInMonth, (int)tempDate.DayOfWeek, _FirstDayOfWeek.Value))
            {
                Grid.SetRow(_Day, rowCount);
                Grid.SetColumn(_Day, colCount);
                grdCollection.Children.Add(_Day);

                if (colCount == 6)
                {
                    colCount = 0;
                    rowCount++;
                }
                else
                    colCount++;
            }

            _DayCollection = PopulateDays(_CurrentYear, _CurrentMonth, _FirstDayOfWeek.Value, ColumnWidth, RowHeight, DisplayMode);

            foreach (ucDay _Day in _DayCollection)
            {
                _Day.CalendarDayButtonMouseDown += new MouseButtonEventHandler(Day_ButtonMouseDown);
                _Day.CalendarDayButtonMouseUp += new MouseButtonEventHandler(Day_ButtonMouseUp);
                _Day.MouseEnter += new MouseEventHandler(Day_MouseEnter);
                _Day.MouseLeave += new MouseEventHandler(Day_MouseLeave);

                Grid.SetRow(_Day, rowCount);
                Grid.SetColumn(_Day, colCount);
                grdCollection.Children.Add(_Day);

                if (colCount == 6)
                {
                    colCount = 0;
                    rowCount++;
                }
                else
                    colCount++;
            }

            PlayAnimation();
        }
        #endregion

        #region HeaderDisplay_Click
        private void HeaderDisplay_Click(System.Object sender, Events.DetailsHeaderClickedEventArgs e)
        {
            switch (DateView)
            {
                case Enumerations.CurrentDateView.Year:
                    DateView = Enumerations.CurrentDateView.Decade;
                    PopulateCalendar();
                    break;
                case Enumerations.CurrentDateView.Month:
                    DateView = Enumerations.CurrentDateView.Year;
                    ucCalendarItem _Year = new ucCalendarItem();
                    _Year.Value = _CurrentYear;
                    Year_Selected(_Year, null);
                    break;
            }
        }
        #endregion

        #region HeaderLeft_Click
        private void HeaderLeft_Click(System.Object sender, Events.LeftHeaderClickedEventArgs e)
        {
            switch (DateView)
            {
                case Enumerations.CurrentDateView.Decade:
                    _LastYear = _FirstYear;
                    _FirstYear = _FirstYear - 11;
                    PopulateCalendar();
                    break;
                case Enumerations.CurrentDateView.Year:
                    _CurrentYear = _CurrentYear - 1;
                    ucCalendarItem _Year = new ucCalendarItem();
                    _Year.Value = _CurrentYear;
                    Year_Selected(_Year, null);
                    break;
                case Enumerations.CurrentDateView.Month:
                    NextPrevious_Month("Previous");
                    ucCalendarItem _Month = new ucCalendarItem();
                    _Month.Value = _CurrentMonth;
                    Month_Selected(_Month, null);
                    break;
            }
        }
        #endregion

        #region HeaderRight_Click
        private void HeaderRight_Click(System.Object sender, Events.RightHeaderClickedEventArgs e)
        {
            switch (DateView)
            {
                case Enumerations.CurrentDateView.Decade:
                    _FirstYear = _LastYear;
                    _LastYear = _LastYear + 11;
                    PopulateCalendar();
                    break;
                case Enumerations.CurrentDateView.Year:
                    _CurrentYear = _CurrentYear + 1;
                    ucCalendarItem _Year = new ucCalendarItem();
                    _Year.Value = _CurrentYear;
                    Year_Selected(_Year, null);
                    break;
                case Enumerations.CurrentDateView.Month:
                    NextPrevious_Month("Next");
                    ucCalendarItem _Month = new ucCalendarItem();
                    _Month.Value = _CurrentMonth;
                    Month_Selected(_Month, null);
                    break;
            }
        }
        #endregion

        #region Day_MouseEnter
        private void Day_MouseEnter(object sender, MouseEventArgs e)
        {
            ucDay _CurrentDay = sender as ucDay;
            if (_DayMouseLeftButtonDown && _CurrentDay != null)
            {
                _MultiSelectionEndDate = new DateTime(_CurrentYear, _CurrentMonth, _CurrentDay.Value);

                _CurrentDay.BorderTopFill = new SolidColorBrush(Colors.Orange);
                _CurrentDay.BorderBottomFill = new SolidColorBrush(Colors.Orange);
                _CurrentDay.IsSelected = !_CurrentDay.IsSelected;
            }
        }
        #endregion

        #region Day_MouseLeave
        private void Day_MouseLeave(object sender, MouseEventArgs e)
        {
            if (_DayMouseLeftButtonDown)
            {
                ucDay _CurrentDay = sender as ucDay;
                _CurrentDay.ReleaseMouseCapture();

                if (DownEventArg != null)
                    _CurrentDay.SendMouseUpEvent(DownEventArg);
            }
        }
        #endregion

        #region Day_ButtonMouseDown
        private void Day_ButtonMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (DisplayMode == Enumerations.DisplayMode.Selection)
            {
                ucDay _CurrentDay = (ucDay)sender;
                DateTime selectedDate = new DateTime(_CurrentYear, _CurrentMonth, _CurrentDay.Value);

                foreach (ucDay _Day in _DayCollection)
                    _Day.IsSelected = false;

                _MultiSelectionStartDate = selectedDate;

                if (SelectionMode == Enumerations.SelectionMode.Multiple)
                {
                    _DayMouseLeftButtonDown = true;
                    _CurrentDay.IsSelected = !_CurrentDay.IsSelected;
                }
                else if (SelectionMode == Enumerations.SelectionMode.Single)
                    _CurrentDay.IsSelected = !_CurrentDay.IsSelected;
            }
        }
        #endregion

        #region Day_ButtonMouseUp
        private void Day_ButtonMouseUp(object sender, MouseButtonEventArgs e)
        {
            if (DisplayMode == Enumerations.DisplayMode.Selection)
            {
                ucDay _CurrentDay = (ucDay)sender;
                DateTime selectedDate = new DateTime(_CurrentYear, _CurrentMonth, _CurrentDay.Value);

                if (SelectionMode == Enumerations.SelectionMode.Multiple)
                {
                    _DayMouseLeftButtonDown = false;

                    if (_MultiSelectionStartDate.HasValue)
                    {
                        foreach (DateTime item in SelectedDates)
                            _RemovedDates.Add(item);

                        SelectedDates.ClearInternal();
                        AddSelection(selectedDate);
                        return;
                    }
                }
                else if (SelectionMode == Enumerations.SelectionMode.Single)
                {
                    if (_CurrentDay.IsSelected)
                        AddSelection(selectedDate);
                    else
                        AddSelection(_MultiSelectionStartDate.Value);
                }
            }
        }
        #endregion

        #region OnSelectedDatesCollectionChanged
        public void OnSelectedDatesCollectionChanged(SelectionChangedEventArgs e)
        {
            if (SelectedDatesChanged != null)
                SelectedDatesChanged(this, e);
        }
        #endregion

        #region cOpts_OptionsLoaded
        private void cOpts_OptionsLoaded(object sender, SLControlLibrary.Resources.Controls.Calendar.ClassicCalendar.Events.OptionsLoadedEventArgs e)
        {
            _SelectionCollection = e.SelectionCollection;
            _DateRangeCollection = e.RangeCollection;
            PopulateCalendar();
        }
        #endregion
        #endregion

        #region Methods
        #region OnApplyTemplate
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _Header = (ucHeader)base.GetTemplateChild("Header");
            grdCollection = (Grid)base.GetTemplateChild("grdCollection");
            _BrdRoot = (Border)base.GetTemplateChild("_BrdRoot");
            sbAnimate = (Storyboard)base.GetTemplateChild("sbAnimate");
            AnimateHeight = (SplineDoubleKeyFrame)base.GetTemplateChild("AnimateHeight");
            AnimateWidth = (SplineDoubleKeyFrame)base.GetTemplateChild("AnimateWidth");
            AnimateLeft = (SplineDoubleKeyFrame)base.GetTemplateChild("AnimateLeft");
            AnimateTopStart = (SplineDoubleKeyFrame)base.GetTemplateChild("AnimateTopStart");
            AnimateTopEnd = (SplineDoubleKeyFrame)base.GetTemplateChild("AnimateTopEnd");

            if (_Header == null) return;

            _Header.LeftValueEvent += HeaderLeft_Click;
            _Header.RightValueEvent += HeaderRight_Click;
            _Header.DetailsValueEvent += HeaderDisplay_Click;

            if (_CurrentYear == 0)
                _CurrentYear = DateTime.Now.Year;

            if (_CurrentMonth == 0)
                _CurrentMonth = DateTime.Now.Month;

            _FirstDayOfWeek = DayOfWeek.Sunday;
            _ThisYear = _CurrentYear;
            _LastYear = _ThisYear + (_Decade - Int32.Parse(_ThisYear.ToString().Substring(3)));
            _FirstYear = _LastYear - 11;

            _SelectionCollection = new DaySelectionCollection();
            _DateRangeCollection = new DateRangeCollection();
            _YearCollection = new YearCollection();
            _MonthCollection = new MonthCollection();
            _DayCollection = new DayCollection();
            SelectedDates = new SLControlLibrary.Resources.Controls.Calendar.ClassicCalendar.BusinessEntities.SelectedDatesCollection(this);

            IsControlLoaded = true;

            if (DisplayMode == Enumerations.DisplayMode.Display)
            {
                CalendarOptions _cOpts = new CalendarOptions();
                _cOpts.OptionsLoaded += new SLControlLibrary.Resources.Controls.Calendar.ClassicCalendar.Events.OptionsLoadedHandler(cOpts_OptionsLoaded);
                _cOpts.RequestXML(CalendarType);
            }
            else
                PopulateCalendar();

            CheckSelectedDate();
        }
        #endregion

        #region Dependency Methods
        #region OnSelectedDate_Changed
        protected virtual void OnSelectedDate_Changed(DependencyPropertyChangedEventArgs e)
        {
            SelectedDate = (DateTime)e.NewValue;
            if (IsControlLoaded)
                CheckSelectedDate();
        }
        #endregion

        #region OnDateView_Changed
        protected virtual void OnDateView_Changed(DependencyPropertyChangedEventArgs e)
        {
            DateView = (Enumerations.CurrentDateView)e.NewValue;
            if (IsControlLoaded)
                PopulateCalendar();
        }
        #endregion

        #region OnControlHeight_Changed
        protected virtual void OnControlHeight_Changed(DependencyPropertyChangedEventArgs e)
        {
            ControlHeight = double.Parse(e.NewValue.ToString());
            if (IsControlLoaded)
                PopulateCalendar();
        }
        #endregion

        #region OnControlWidth_Changed
        protected virtual void OnControlWidth_Changed(DependencyPropertyChangedEventArgs e)
        {
            ControlWidth = double.Parse(e.NewValue.ToString());
            if (IsControlLoaded)
                PopulateCalendar();
        }
        #endregion

        #region OnHeaderBackground_Changed
        protected virtual void OnHeaderBackground_Changed(DependencyPropertyChangedEventArgs e)
        {
            if (_Header != null)
                _Header.Background = (SolidColorBrush)e.NewValue;
        }
        #endregion

        #region OnWeekHeaderForeground_Changed
        protected virtual void OnWeekHeaderForeground_Changed(DependencyPropertyChangedEventArgs e)
        {
            if (grdCollection != null && grdCollection.Children.Count > 0)
            {
                if (DateView == Enumerations.CurrentDateView.Month)
                {
                    foreach (ucDay _Day in grdCollection.Children)
                    {
                        if (_Day.IsWeekHeader)
                            _Day.TextForeground = (SolidColorBrush)e.NewValue;
                    }
                }
            }
        }
        #endregion

        #region OnHeaderForeground_Changed
        protected virtual void OnHeaderForeground_Changed(DependencyPropertyChangedEventArgs e)
        {
            if (_Header != null)
                _Header.Foreground = (SolidColorBrush)e.NewValue;
        }
        #endregion

        #region OnYearForeground_Changed
        protected virtual void OnYearForeground_Changed(DependencyPropertyChangedEventArgs e)
        {
            if (_YearCollection != null)
            {
                foreach (ucCalendarItem _Year in _YearCollection)
                    _Year.Foreground = (SolidColorBrush)e.NewValue;
            }
        }
        #endregion

        #region OnMonthForeground_Changed
        protected virtual void OnMonthForeground_Changed(DependencyPropertyChangedEventArgs e)
        {
            if (_MonthCollection != null)
            {
                foreach (ucCalendarItem _Month in _MonthCollection)
                    _Month.Foreground = (SolidColorBrush)e.NewValue;
            }
        }
        #endregion

        #region OnAllowMonthNavigation_Changed
        protected virtual void OnAllowMonthNavigation_Changed(DependencyPropertyChangedEventArgs e)
        {
            AllowMonthNavigation = (bool)e.NewValue;
        }
        #endregion
        #endregion

        #region SetBindings
        private void SetBindings()
        {
            var vm = new CalendarVM { DateView = this.DateView, ControlHeight = this.ControlHeight, ControlWidth = this.ControlWidth, AllowMonthNavigation = this.AllowMonthNavigation };
            this.DataContext = vm;

            Binding b1 = new Binding() { Path = new PropertyPath("DateView"), Mode = BindingMode.TwoWay, Source = vm };
            this.SetBinding(ucCalendar.DateViewProperty, b1);

            Binding b2 = new Binding() { Path = new PropertyPath("ControlHeight"), Mode = BindingMode.TwoWay, Source = vm };
            this.SetBinding(ucCalendar.ControlHeightProperty, b2);

            Binding b3 = new Binding() { Path = new PropertyPath("ControlWidth"), Mode = BindingMode.TwoWay, Source = vm };
            this.SetBinding(ucCalendar.ControlWidthProperty, b3);

            Binding b4 = new Binding() { Path = new PropertyPath("AllowMonthNavigation"), Mode = BindingMode.TwoWay, Source = vm };
            this.SetBinding(ucCalendar.AllowMonthNavigationProperty, b4);

            if (_Header != null)
                _Header.SetBinding(ucHeader.AllowMonthNavigationProperty, b4);
        }
        #endregion

        #region PopulateCalendar
        private void PopulateCalendar()
        {
            switch (DateView)
            {
                case Enumerations.CurrentDateView.Decade:
                    SetHeaderValue(_FirstYear + " - " + _LastYear);

                    YearCollection _YearCollection = PopulateYears(_LastYear, _FirstYear);

                    SortValue(ref _YearCollection, SLControlLibrary.Resources.Common.Enumerations.SortDirection.Descending);

                    grdCollection.Children.Clear();

                    grdCollection.ColumnDefinitions.Clear();
                    grdCollection.RowDefinitions.Clear();

                    double ColumnWidth = ControlWidth / 4;
                    double RowHeight = (ControlHeight - _Header.DisplayHeight) / 3;

                    ColumnDefinition cd1 = new ColumnDefinition();
                    cd1.Width = new GridLength(ColumnWidth, GridUnitType.Pixel);
                    grdCollection.ColumnDefinitions.Add(cd1);
                    cd1 = new ColumnDefinition();
                    cd1.Width = new GridLength(ColumnWidth, GridUnitType.Pixel);
                    grdCollection.ColumnDefinitions.Add(cd1);
                    cd1 = new ColumnDefinition();
                    cd1.Width = new GridLength(ColumnWidth, GridUnitType.Pixel);
                    grdCollection.ColumnDefinitions.Add(cd1);
                    cd1 = new ColumnDefinition();
                    cd1.Width = new GridLength(ColumnWidth, GridUnitType.Pixel);
                    grdCollection.ColumnDefinitions.Add(cd1);

                    RowDefinition rd1 = new RowDefinition();
                    rd1.Height = new GridLength(RowHeight, GridUnitType.Pixel);
                    grdCollection.RowDefinitions.Add(rd1);
                    rd1 = new RowDefinition();
                    rd1.Height = new GridLength(RowHeight, GridUnitType.Pixel);
                    grdCollection.RowDefinitions.Add(rd1);
                    rd1.Height = new GridLength(RowHeight, GridUnitType.Pixel);
                    rd1 = new RowDefinition();
                    grdCollection.RowDefinitions.Add(rd1);

                    int rowCount = 0;
                    int colCount = 0;

                    foreach (ucCalendarItem _Year in _YearCollection)
                    {
                        _Year.ValueEvent += Year_Selected;
                        _Year.Foreground = YearForeground;
                        _Year.Height = RowHeight;
                        _Year.Width = ColumnWidth;

                        Grid.SetRow(_Year, rowCount);
                        Grid.SetColumn(_Year, colCount);
                        grdCollection.Children.Add(_Year);

                        if (colCount == 3)
                        {
                            colCount = 0;
                            rowCount++;
                        }
                        else
                            colCount++;
                    }

                    PlayAnimation();
                    break;
                case Enumerations.CurrentDateView.Year:
                    ucCalendarItem _year = new ucCalendarItem();
                    _year.Value = _CurrentYear;
                    Year_Selected(_year, null);
                    break;
                case Enumerations.CurrentDateView.Month:
                    ucCalendarItem _month = new ucCalendarItem();
                    _month.Value = _CurrentMonth;
                    Month_Selected(_month, null);
                    break;
            }
        }
        #endregion

        #region SetHeaderValue
        private void SetHeaderValue(string _Value)
        {
            _Header.Value = _Value;
            _Header.ButtonHeight = (ControlHeight * 0.2);
            _Header.ButtonWidth = (ControlWidth * 0.1);
            _Header.DisplayWidth = ControlWidth - (_Header.ButtonWidth * 2);
            _Header.DisplayHeight = (_BrdRoot.Height * 0.2);
            _Header.AllowMonthNavigation = AllowMonthNavigation;
        }
        #endregion

        #region NextPrevious_Month
        private void NextPrevious_Month(string _Value)
        {
            if (_Value == "Next")
            {
                if (_CurrentMonth == 12)
                    _CurrentMonth = _MonthCollection[0].Value;
                else
                    _CurrentMonth = _MonthCollection[_CurrentMonth].Value;
            }
            else if (_Value == "Previous")
            {
                if (_CurrentMonth == 1)
                    _CurrentMonth = _MonthCollection[_MonthCollection.Count - 1].Value;
                else
                    _CurrentMonth = _MonthCollection[_CurrentMonth - 2].Value;
            }
        }
        #endregion

        #region PlayAnimation
        private void PlayAnimation()
        {
            if (AnimationType == Enumerations.AnimationType.Default)
            {
                SplineDoubleKeyFrame frame = AnimateHeight;
                frame.Value = _BrdRoot.Height - _Header.ActualHeight;

                SplineDoubleKeyFrame frame2 = AnimateWidth;
                frame2.Value = _BrdRoot.Width;

                SplineDoubleKeyFrame frame3 = AnimateLeft;
                frame3.Value = _BrdRoot.Width / 2;

                SplineDoubleKeyFrame frame4 = AnimateTopStart;
                frame4.Value = (_BrdRoot.Height - _Header.ActualHeight) / 2;

                SplineDoubleKeyFrame frame5 = AnimateTopEnd;
                frame5.Value = 0;

                sbAnimate.Begin();
            }
        }
        #endregion

        #region IsSelectionChanged
        private static bool IsSelectionChanged(SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count != e.RemovedItems.Count)
                return true;

            foreach (DateTime addedDate in e.AddedItems)
            {
                if (!e.RemovedItems.Contains(addedDate))
                    return true;
            }

            return false;
        }
        #endregion

        #region AddSelection
        private void AddSelection(DateTime _CurrentDate)
        {
            if (SelectionMode == Enumerations.SelectionMode.Multiple)
            {
                _MultiSelectionEndDate = _CurrentDate;

                if (_MultiSelectionEndDate != null && _MultiSelectionStartDate != null)
                {
                    _IsMouseSelection = true;
                    SelectedDates.AddRange(_MultiSelectionStartDate.Value, _MultiSelectionEndDate.Value);
                }
            }
            else if (SelectionMode == Enumerations.SelectionMode.Single)
            {
                SelectedDates.AddDateToList(_CurrentDate);
            }
        }
        #endregion

        #region CheckSelectedDate
        private void CheckSelectedDate()
        {
            if (SelectedDates == null) SelectedDates = new BusinessEntities.SelectedDatesCollection(this);

            if (_DayCollection != null)
            {
                foreach (ucDay _Day in _DayCollection)
                {
                    if (_CurrentYear == SelectedDate.Year && _CurrentMonth == SelectedDate.Month && _Day.Value == SelectedDate.Day)
                    {
                        _Day.IsSelected = true;
                        break;
                    }
                }
            }

            AddSelection(SelectedDate);
        }
        #endregion

        #region SortValue
        private void SortValue(ref YearCollection _YearProvider, SLControlLibrary.Resources.Common.Enumerations.SortDirection _Direction)
        {
            List<ucCalendarItem> _TempList = _YearProvider.ToList();
            _YearProvider.Clear();
            switch (_Direction)
            {
                case SLControlLibrary.Resources.Common.Enumerations.SortDirection.Ascending:
                    _TempList.Sort((ucCalendarItem x, ucCalendarItem y) => (y.Value.CompareTo(x.Value)));
                    break;
                case SLControlLibrary.Resources.Common.Enumerations.SortDirection.Descending:
                    _TempList.Sort((ucCalendarItem x, ucCalendarItem y) => (x.Value.CompareTo(y.Value)));
                    break;
            }

            foreach (ucCalendarItem _Item in _TempList)
                _YearProvider.Add(_Item);
        }
        #endregion

        #region PopulateYears
        private YearCollection PopulateYears(int _LastYear, int _FirstYear)
        {
            _YearCollection = new YearCollection();

            for (int _YearValue = _LastYear; _YearValue >= _FirstYear; _YearValue += -1)
            {
                ucCalendarItem _Year = new ucCalendarItem();
                _Year.Value = _YearValue;
                _Year.DisplayMode = DisplayMode;

                if (_Year.Value == DateTime.Today.Year)
                {
                    _Year.BorderBrush = new SolidColorBrush(Colors.Blue);
                    _Year.BorderThickness = new Thickness(1);
                    _Year.Background = new SolidColorBrush();
                }

                _YearCollection.Add(_Year);
            }

            return _YearCollection;
        }
        #endregion

        #region PopulateMonths
        private MonthCollection PopulateMonths(int _Year)
        {
            _MonthCollection = new MonthCollection();

            for (int _MonthValue = 1; _MonthValue <= 12; _MonthValue++)
            {
                ucCalendarItem _Month = new ucCalendarItem();
                _Month.Value = _MonthValue;
                _Month.DisplayMode = DisplayMode;

                if (_Month.Value == DateTime.Today.Month && _Year == DateTime.Today.Year)
                {
                    _Month.BorderBrush = new SolidColorBrush(Colors.Blue);
                    _Month.BorderThickness = new Thickness(1);
                    _Month.Background = new SolidColorBrush();
                }

                _MonthCollection.Add(_Month);
            }

            return _MonthCollection;
        }
        #endregion

        #region PopulateWeekHeader
        private StackPanel PopulateWeekHeader(double _ParentWidth, Orientation _Orientation, SolidColorBrush Foreground)
        {
            StackPanel sp = new StackPanel();
            sp.Width = _ParentWidth;
            sp.Orientation = _Orientation;
            double _Width = (_ParentWidth / 7);

            for (int i = 1; i <= 7; i++)
            {
                ucDay _Day = new ucDay();
                _Day.IsWeekHeader = true;
                _Day.Value = i;
                _Day.Margin = new Thickness(0, 0, 0, 1.15);
                _Day.Width = _Width;
                _Day.TextForeground = Foreground;
                sp.Children.Add(_Day);
            }

            return sp;
        }
        #endregion

        #region PopulateWeekHeaderCollection
        private DayCollection PopulateWeekHeaderCollection(double _Width, double _Height, Orientation _Orientation, SolidColorBrush Foreground)
        {
            DayCollection _Days = new DayCollection();

            for (int i = 1; i <= 7; i++)
            {
                ucDay _Day = new ucDay();
                _Day.IsWeekHeader = true;
                _Day.Value = i;
                _Day.Margin = new Thickness(0, 0, 0, 1.15);
                _Day.Width = _Width;
                _Day.Height = _Height;
                _Day.TextForeground = Foreground;

                _Days.Add(_Day);
            }

            return _Days;
        }
        #endregion

        #region PopulateWeekHeaderSpacer
        private DayCollection PopulateWeekSpacer(double _Width, double _Height, int _DaysInMonth, int _FirstDayInMonth, DayOfWeek _FirstDayOfWeek)
        {
            DayCollection _DayCollection = new DayCollection();

            if (_FirstDayInMonth > (int)_FirstDayOfWeek)
            {
                for (int i = 1; i <= (_FirstDayInMonth - (int)_FirstDayOfWeek); i++)
                {
                    ucDay _Day = new ucDay();
                    _Day.Value = 0;
                    _Day.Width = _Width;
                    _Day.Height = _Height;
                    _DayCollection.Add(_Day);
                }
            }

            return _DayCollection;
        }
        #endregion

        #region PopulateDays
        private DayCollection PopulateDays(int _Year, int _Month, DayOfWeek _FirstDayOfWeek, double _Width, double _Height, Enumerations.DisplayMode DisplayMode)
        {
            _DayCollection = new DayCollection();

            for (int _DayValue = 1; _DayValue <= DateTime.DaysInMonth(_Year, _Month); _DayValue++)
            {
                ucDay _Day = new ucDay();
                _Day.Width = _Width - 2;
                _Day.Height = _Height;
                _Day.Margin = new Thickness(.5, .5, .5, .5);

                ProcessDay(ref _Day, _Year, _Month, _DayValue, _FirstDayOfWeek, DisplayMode);
                _DayCollection.Add(_Day);
            }

            return _DayCollection;
        }
        #endregion

        #region ProcessDay
        private void ProcessDay(ref ucDay _Day, int _Year, int _Month, int _DayValue, DayOfWeek _FirstDayOfWeek, Enumerations.DisplayMode DisplayMode)
        {
            DateTime now = new System.DateTime(_Year, _Month, _DayValue);

            _Day.Value = _DayValue;

            if (now == DateTime.Today)
            {
                _Day.BorderBrush = new SolidColorBrush(Colors.Blue);
                _Day.BorderThickness = new Thickness(2, 2, 2, 2);
                _Day.Background = new SolidColorBrush();
            }

            if (DisplayMode == Enumerations.DisplayMode.Display)
                ProcessDaySelection(ref _Day, _Year, _Month);
            else
                _Day.DisplayMode = DisplayMode;

            if (_DayValue == 1)
                ProcessFirstLastOfMonth(ref _Day, _Year, _Month, "First", DisplayMode);
            else if (_DayValue == DateTime.DaysInMonth(_Year, _Month))
                ProcessFirstLastOfMonth(ref _Day, _Year, _Month, "Last", DisplayMode);
        }
        #endregion

        #region ProcessDaySelection
        private void ProcessDaySelection(ref ucDay _Day, int _Year, int _Month)
        {
            DateTime _CurrentDate = new DateTime(_Year, _Month, _Day.Value);
            bool _IsInRange = false;

            foreach (DateRange _Range in _DateRangeCollection)
            {
                DateRange _TempRange = _Range;

                if (_CurrentDate >= _Range.InDate && _CurrentDate <= _Range.OutDate)
                {
                    if (_CurrentDate == _Range.InDate)
                    {
                        _Day.BottomSelection = _SelectionCollection.Where((DaySelection n) => n.Value == _TempRange.DaySelectionValue).Single();
                        _IsInRange = true;
                        _Day.IsFirstInRange = true;
                        if (!_Day.BottomSelection.HalfDay)
                            _Day.TopSelection = _SelectionCollection.Where((DaySelection n) => n.Value == _TempRange.DaySelectionValue).Single();
                    }
                    else if (_CurrentDate == _Range.OutDate)
                    {
                        _Day.IsLastInRange = true;
                        _Day.TopSelection = _SelectionCollection.Where((DaySelection n) => n.Value == _TempRange.DaySelectionValue).Single();
                        _IsInRange = true;
                        if (!_Day.TopSelection.HalfDay)
                            _Day.BottomSelection = _SelectionCollection.Where((DaySelection n) => n.Value == _TempRange.DaySelectionValue).Single();
                    }
                    else
                    {
                        _Day.TopSelection = _SelectionCollection.Where((DaySelection n) => n.Value == _TempRange.DaySelectionValue).Single();
                        _Day.BottomSelection = _Day.TopSelection;
                        _IsInRange = true;
                    }
                }
            }

            if (_IsInRange && _Day.TopSelection == null)
                _Day.TopSelection = _SelectionCollection.Where((DaySelection n) => n.Value == -1).Single();
            else if (_IsInRange && _Day.BottomSelection == null)
                _Day.BottomSelection = _SelectionCollection.Where((DaySelection n) => n.Value == -1).Single();
            else if (!_IsInRange)
            {
                _Day.TopSelection = _SelectionCollection.Where((DaySelection n) => n.Value == -1).Single();
                _Day.BottomSelection = _SelectionCollection.Where((DaySelection n) => n.Value == -1).Single();
            }
        }
        #endregion

        #region ProcessFirstLastOfMonth
        private void ProcessFirstLastOfMonth(ref ucDay _Day, int _Year, int _Month, string _FirstLastOfMonth, Enumerations.DisplayMode DisplayMode)
        {
            if (_FirstLastOfMonth == "First")
            {
                if (_Month == 1)
                {
                    _Month = 12;
                    _Year = _Year - 1;
                }
                else
                    _Month = _Month - 1;

                int _DayValue = DateTime.DaysInMonth(_Year, _Month);
                ucDay _NewDay = new ucDay();
                _NewDay.Value = _DayValue;

                if (DisplayMode == Enumerations.DisplayMode.Display)
                {
                    ProcessDaySelection(ref _NewDay, _Year, _Month);
                    _Day.TopSelection = _NewDay.BottomSelection;
                }
            }
            else if (_FirstLastOfMonth == "Last")
            {
                if (_Month == 12)
                {
                    _Month = 1;
                    _Year = _Year + 1;
                }
                else
                    _Month = _Month + 1;

                int _DayValue = 1;
                ucDay _NewDay = new ucDay();
                _NewDay.Value = _DayValue;

                if (DisplayMode == Enumerations.DisplayMode.Display)
                {
                    ProcessDaySelection(ref _NewDay, _Year, _Month);
                    _Day.BottomSelection = _NewDay.TopSelection;
                }
            }
        }
        #endregion
        #endregion
    }
}
